home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / hard / drivr / cyberx10.lha / CyberX10 / Source / X10UpDown.c < prev   
Text File  |  1992-11-06  |  14KB  |  599 lines

  1.  
  2.  /*
  3.   * this contains the routines used to upload or download a program from/to
  4.   * the CP290's memory
  5.   */
  6.  
  7. static struct TimerEvent_t {
  8.     UBYTE te_Mode;
  9.     UBYTE te_DOW;
  10.     UBYTE te_Hour;
  11.     UBYTE te_Minute;
  12.     UBYTE te_UnitMap[2];
  13.     UBYTE te_HouseCode;
  14.     UBYTE te_LevelFunction;
  15. } TimerTable[128];
  16. static int TimerTablePos;
  17.  
  18. static struct GraphicsData_t {
  19.     UBYTE gd_Graphic1;
  20.     UBYTE gd_Graphic2;
  21. } GraphicTable[256];
  22. static int GraphicsTablePos;
  23.  
  24. #define DOWNLOAD_TEMPLATE "TIMER/S,GRAPHICS/S,NORMAL/S,SECURITY/S,TODAY/S,TOMORROW/S,EVERYDAY/S,WEEKENDS/S,WEEKDAYS/S,MON/S,TUE/S,WED/S,THU/S,FRI/S,SAT/S,SUN/S,HOUR/K/N,MINUTE/K/N,HOUSECODE/K,ON/S,OFF/S,DIM/K/N,SPECIALS/M/A"
  25.  
  26. enum DownloadArgs {
  27.     ARG_TIMER,
  28.     ARG_GRAPHICS,
  29.     ARG_NORMAL,
  30.     ARG_SECURITY,
  31.     ARG_TODAY,
  32.     ARG_TOMORROW,
  33.     ARG_EVERYDAY,
  34.     ARG_WEEKENDS,
  35.     ARG_WEEKDAYS,
  36.     ARG_MON,
  37.     ARG_TUE,
  38.     ARG_WED,
  39.     ARG_THU,
  40.     ARG_FRI,
  41.     ARG_SAT,
  42.     ARG_SUN,
  43.     ARG_HOUR,
  44.     ARG_MINUTE,
  45.     ARG_HOUSECODE,
  46.     ARG_ON,
  47.     ARG_OFF,
  48.     ARG_DIM,
  49.     ARG_SPECIALS,
  50.     ARG_sizeof
  51. };
  52.  
  53.  /* prototypes for our private functions in this file */
  54.  
  55. static BOOL SendUploadRequest(BOOL RequestGraphics);
  56. static UWORD ReadNextData(int DataLength, STRPTR Buffer);
  57.  
  58.  /* parse a file and download it to the CP290 */
  59.  
  60. void X10Download(STRPTR filename)
  61. {
  62.     BPTR fh;
  63.     int index;
  64.     UBYTE Buf[40];
  65.  
  66.     struct RDArgs *RArgs1, *RArgs2;
  67.     STRPTR ArgArray[ARG_sizeof];
  68.  
  69.     STRPTR LineBuf;
  70.     ULONG line;
  71.  
  72.     STRPTR *Specials;
  73.     UWORD *uwordPtr;
  74.  
  75.     int houseCode;
  76.  
  77.     line = TimerTablePos = GraphicsTablePos = 0;
  78.  
  79.     if (LineBuf = AllocVec(BIG_BUF_SIZE, 0)) {
  80.         if (fh = Open(filename, MODE_OLDFILE)) {
  81.             while (FGets(fh, LineBuf, BIG_BUF_SIZE_BASE)) {
  82.                 line++;
  83.  
  84.                 if (LineBuf[0] == '#' || LineBuf[0] == '\n')
  85.                     continue;
  86.  
  87.                 strcpy(&LineBuf[strlen(LineBuf)], "\n");
  88.  
  89.                 if (RArgs1 = AllocDosObject(DOS_RDARGS, TAG_DONE)) {
  90.                     RArgs1->RDA_Source.CS_Buffer = LineBuf;
  91.                     RArgs1->RDA_Source.CS_Length = strlen(LineBuf);
  92.                     RArgs1->RDA_Source.CS_CurChr = 0L;
  93.                     RArgs1->RDA_Flags |= RDAF_NOPROMPT;
  94.  
  95.                     memset(ArgArray, 0, sizeof(ArgArray));
  96.  
  97.                     RArgs2 = ReadArgs(DOWNLOAD_TEMPLATE, (LONG *) & ArgArray, RArgs1);
  98.  
  99.                     if (RArgs2) {
  100.                         Specials = (STRPTR *) ArgArray[ARG_SPECIALS];
  101.  
  102.                         if (ArgArray[ARG_TIMER]) {
  103.                             if (TimerTablePos < 128) {
  104.                                 if (ArgArray[ARG_SECURITY])
  105.                                     TimerTable[TimerTablePos].te_Mode = 9;
  106.                                 else if (ArgArray[ARG_TODAY])
  107.                                     TimerTable[TimerTablePos].te_Mode = 4;
  108.                                 else if (ArgArray[ARG_TOMORROW])
  109.                                     TimerTable[TimerTablePos].te_Mode = 2;
  110.                                 else
  111.                                     TimerTable[TimerTablePos].te_Mode = 8;
  112.  
  113.                                 TimerTable[TimerTablePos].te_DOW = 0;
  114.  
  115.                                 if (!ArgArray[ARG_TODAY] && !ArgArray[ARG_TOMORROW]) {
  116.                                     if (ArgArray[ARG_EVERYDAY])
  117.                                         TimerTable[TimerTablePos].te_DOW = 64 + 32 + 16 + 8 + 4 + 2 + 1;
  118.                                     else if (ArgArray[ARG_WEEKENDS])
  119.                                         TimerTable[TimerTablePos].te_DOW = 64 + 32;
  120.                                     else if (ArgArray[ARG_WEEKDAYS])
  121.                                         TimerTable[TimerTablePos].te_DOW = 16 + 8 + 4 + 2 + 1;
  122.  
  123.                                     if (ArgArray[ARG_SUN])
  124.                                         TimerTable[TimerTablePos].te_DOW |= 64;
  125.                                     if (ArgArray[ARG_SAT])
  126.                                         TimerTable[TimerTablePos].te_DOW |= 32;
  127.                                     if (ArgArray[ARG_FRI])
  128.                                         TimerTable[TimerTablePos].te_DOW |= 16;
  129.                                     if (ArgArray[ARG_THU])
  130.                                         TimerTable[TimerTablePos].te_DOW |= 8;
  131.                                     if (ArgArray[ARG_WED])
  132.                                         TimerTable[TimerTablePos].te_DOW |= 4;
  133.                                     if (ArgArray[ARG_TUE])
  134.                                         TimerTable[TimerTablePos].te_DOW |= 2;
  135.                                     if (ArgArray[ARG_MON])
  136.                                         TimerTable[TimerTablePos].te_DOW |= 1;
  137.                                 }
  138.  
  139.                                 if (ArgArray[ARG_HOUR])
  140.                                     TimerTable[TimerTablePos].te_Hour = *((LONG *) ArgArray[ARG_HOUR]);
  141.                                 else
  142.                                     TimerTable[TimerTablePos].te_Hour = (UBYTE) - 1;
  143.  
  144.                                 if (ArgArray[ARG_MINUTE])
  145.                                     TimerTable[TimerTablePos].te_Minute = *((LONG *) ArgArray[ARG_MINUTE]);
  146.                                 else
  147.                                     TimerTable[TimerTablePos].te_Minute = (UBYTE) - 1;
  148.  
  149.                                 houseCode = X10GetHC(*ArgArray[ARG_HOUSECODE]);
  150.                                 if (houseCode != -1)
  151.                                     TimerTable[TimerTablePos].te_HouseCode = HouseCode[houseCode];
  152.  
  153.                                 if (ArgArray[ARG_ON])
  154.                                     TimerTable[TimerTablePos].te_LevelFunction = 2;
  155.                                 else if (ArgArray[ARG_DIM])
  156.                                     TimerTable[TimerTablePos].te_LevelFunction = 5 | ((*((LONG *) ArgArray[ARG_DIM]) - 1) << 4L);
  157.                                 else
  158.                                     TimerTable[TimerTablePos].te_LevelFunction = 3;
  159.  
  160.                                 TimerTable[TimerTablePos].te_UnitMap[0] = 0;
  161.                                 TimerTable[TimerTablePos].te_UnitMap[1] = 0;
  162.  
  163.                                 while (*Specials) {
  164.                                     index = (atol(*Specials++) - 1) & 0x0F;
  165.  
  166.                                     if (index < 8)
  167.                                         TimerTable[TimerTablePos].te_UnitMap[0] |= 1L << (7 - index);
  168.                                     else
  169.                                         TimerTable[TimerTablePos].te_UnitMap[1] |= 1L << (7 - (index - 8));
  170.                                 }
  171.  
  172.                                 if ((TimerTable[TimerTablePos].te_DOW || TimerTable[TimerTablePos].te_Mode == 4 || TimerTable[TimerTablePos].te_Mode == 2) &&
  173.                                     houseCode != -1 && (TimerTable[TimerTablePos].te_UnitMap[0] || TimerTable[TimerTablePos].te_UnitMap[1]) &&
  174.                                     TimerTable[TimerTablePos].te_Hour != -1 && TimerTable[TimerTablePos].te_Minute != -1)
  175.                                     TimerTablePos++;
  176.                                 else
  177.                                     ErrorMsg(MSG_PARSE_ERROR, line, filename);
  178.                             }
  179.                             else
  180.                                 ErrorMsg(MSG_TIMER_TABLE_FULL);
  181.  
  182.                         }
  183.                         else if (ArgArray[ARG_GRAPHICS]) {
  184.                             if (Specials[0] && Specials[1] && !Specials[2]) {
  185.                                 if (GraphicsTablePos < 256) {
  186.                                     GraphicTable[GraphicsTablePos].gd_Graphic1 = atol(Specials[0]);
  187.                                     GraphicTable[GraphicsTablePos++].gd_Graphic2 = atol(Specials[1]);
  188.                                 }
  189.                                 else
  190.                                     ErrorMsg(MSG_GRAPHICS_TABLE_FULL);
  191.                             }
  192.                             else
  193.                                 ErrorMsg(MSG_PARSE_ERROR, line, filename);
  194.                         }
  195.  
  196.                         FreeArgs(RArgs2);
  197.                     }
  198.                     else
  199.                         ErrorMsg(MSG_PARSE_ERROR, line, filename);
  200.  
  201.                     FreeDosObject(DOS_RDARGS, RArgs1);
  202.                 }
  203.                 else
  204.                     ErrorMsg(MSG_NO_RDARGS);
  205.             }
  206.  
  207.             Close(fh);
  208.         }
  209.         else
  210.             ErrorMsg(MSG_COULDNT_OPEN_FILE, filename);
  211.  
  212.         FreeVec(LineBuf);
  213.     }
  214.     else
  215.         ErrorMsg(MSG_OUT_OF_MEMORY);
  216.  
  217.     if (TimerTablePos)
  218.         for (index = 0; index < 128; index++) {
  219.             memset(Buf, 0xFF, 16);
  220.             Buf[16] = 3;
  221.  
  222.             uwordPtr = (UWORD *) & Buf[17];
  223.             *uwordPtr = index * 8;
  224.             Buf[19] = Buf[17];
  225.             Buf[17] = Buf[18];
  226.             Buf[18] = Buf[19];
  227.  
  228.             if (index < TimerTablePos)
  229.                 CopyMem((APTR) & TimerTable[index], &Buf[19], 8);
  230.             else
  231.                 memset(&Buf[19], 0, 8);
  232.  
  233.             Buf[27] = Buf[19] + Buf[20] + Buf[21] + Buf[22] + Buf[23] + Buf[24] + Buf[25] + Buf[26];
  234.  
  235.             ClearSerial();
  236.             SerWrite(Buf, 28);
  237.             if (!X10WaitForAck(FALSE)) {
  238.                 ErrorMsg(MSG_CP290_ERROR_DOWNLOAD);
  239.                 return;
  240.             }
  241.         }
  242.  
  243.     if (GraphicsTablePos)
  244.         for (index = 0; index < 256; index++) {
  245.             memset(Buf, 0xFF, 16);
  246.             Buf[16] = 3;
  247.  
  248.             uwordPtr = (UWORD *) & Buf[17];
  249.             *uwordPtr = index * 2 + 1024;
  250.             Buf[19] = Buf[17];
  251.             Buf[17] = Buf[18];
  252.             Buf[18] = Buf[19];
  253.  
  254.             if (index < GraphicsTablePos)
  255.                 CopyMem((APTR) & GraphicTable[index], &Buf[19], 2);
  256.             else
  257.                 memset(&Buf[19], 0, 2);
  258.  
  259.             Buf[21] = Buf[19] + Buf[20];
  260.  
  261.             ClearSerial();
  262.             SerWrite(Buf, 22);
  263.             if (!X10WaitForAck(FALSE)) {
  264.                 ErrorMsg(MSG_CP290_ERROR_DOWNLOAD);
  265.                 return;
  266.             }
  267.         }
  268. }
  269.  
  270.  /* upload the information stored in the interface and write it to a file */
  271.  
  272. void X10Upload(STRPTR filename)
  273. {
  274.     BPTR fh;
  275.     int index, index2;
  276.     UBYTE Buf[40];
  277.     UBYTE CheckSum;
  278.     UWORD raw;
  279.     STRPTR outText;
  280.  
  281.     /* first try and download all the timer events */
  282.     if (SendUploadRequest(FALSE)) {
  283.         CheckSum = TimerTablePos = 0;
  284.  
  285.         for (index = 0; index < 128; index++) {
  286.             raw = ReadNextData(8, (STRPTR) & TimerTable[TimerTablePos]);
  287.  
  288.             if (raw == TIMEOUT) {
  289.                 ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_TIMEOUT));
  290.                 return;
  291.             }
  292.  
  293.             if (raw != EMPTY) {
  294.                 CheckSum = (CheckSum + raw) & 0xFF;
  295.                 TimerTablePos++;
  296.             }
  297.         }
  298.  
  299.         raw = SerGetRawChar(2);
  300.  
  301.         if (raw == TIMEOUT) {
  302.             ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_TIMEOUT));
  303.             return;
  304.         }
  305.  
  306.         if (raw != CheckSum) {
  307.             ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_CHECKSUM));
  308.             return;
  309.         }
  310.     }
  311.  
  312.     /* next try and download all the graphics data */
  313.     if (SendUploadRequest(TRUE)) {
  314.         CheckSum = GraphicsTablePos = 0;
  315.  
  316.         for (index = 0; index < 256; index++) {
  317.             raw = ReadNextData(2, (STRPTR) & GraphicTable[GraphicsTablePos]);
  318.  
  319.             if (raw == TIMEOUT) {
  320.                 ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_TIMEOUT));
  321.                 return;
  322.             }
  323.  
  324.             if (raw != EMPTY) {
  325.                 CheckSum = (CheckSum + raw) & 0xFF;
  326.                 GraphicsTablePos++;
  327.             }
  328.         }
  329.  
  330.         raw = SerGetRawChar(2);
  331.  
  332.         if (raw == TIMEOUT) {
  333.             ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_TIMEOUT));
  334.             return;
  335.         }
  336.  
  337.         if (raw != CheckSum) {
  338.             ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_CHECKSUM));
  339.             return;
  340.         }
  341.     }
  342.  
  343.     /* now try and write the data to the specified file */
  344.  
  345.     if (fh = Open(filename, MODE_NEWFILE)) {
  346.         if (FPuts(fh, GetString(&LocaleInfo, MSG_COMMENT_TIMER))) {
  347.             ErrorMsg(MSG_IO_ERROR, filename);
  348.             Close(fh);
  349.             return;
  350.         }
  351.  
  352.         for (index = 0; index < TimerTablePos; index++) {
  353.             if (FPuts(fh, "timer ")) {
  354.                 ErrorMsg(MSG_IO_ERROR, filename);
  355.                 Close(fh);
  356.                 return;
  357.             }
  358.  
  359.             switch (TimerTable[index].te_Mode & 0x0F) {
  360.             case 8:
  361.                 outText = "normal ";
  362.                 break;
  363.  
  364.             case 9:
  365.                 outText = "security ";
  366.                 break;
  367.  
  368.             case 4:
  369.                 outText = "today ";
  370.                 break;
  371.  
  372.             case 2:
  373.                 outText = "tomorrow ";
  374.                 break;
  375.  
  376.             default:
  377.                 outText = "";
  378.                 break;
  379.             }
  380.  
  381.             if (FPuts(fh, outText)) {
  382.                 ErrorMsg(MSG_IO_ERROR, filename);
  383.                 Close(fh);
  384.                 return;
  385.             }
  386.  
  387.             if (TimerTable[index].te_DOW == (64 + 32)) {
  388.                 if (FPuts(fh, "weekends ")) {
  389.                     ErrorMsg(MSG_IO_ERROR, filename);
  390.                     Close(fh);
  391.                     return;
  392.                 }
  393.             }
  394.             else if (TimerTable[index].te_DOW == (16 + 8 + 4 + 2 + 1)) {
  395.                 if (FPuts(fh, "weekdays ")) {
  396.                     ErrorMsg(MSG_IO_ERROR, filename);
  397.                     Close(fh);
  398.                     return;
  399.                 }
  400.             }
  401.             else if (TimerTable[index].te_DOW == (64 + 32 + 16 + 8 + 4 + 2 + 1)) {
  402.                 if (FPuts(fh, "everyday ")) {
  403.                     ErrorMsg(MSG_IO_ERROR, filename);
  404.                     Close(fh);
  405.                     return;
  406.                 }
  407.             }
  408.             else {
  409.                 if (TimerTable[index].te_DOW & 64)
  410.                     if (FPuts(fh, "sun ")) {
  411.                         ErrorMsg(MSG_IO_ERROR, filename);
  412.                         Close(fh);
  413.                         return;
  414.                     }
  415.  
  416.                 if (TimerTable[index].te_DOW & 1)
  417.                     if (FPuts(fh, "mon ")) {
  418.                         ErrorMsg(MSG_IO_ERROR, filename);
  419.                         Close(fh);
  420.                         return;
  421.                     }
  422.  
  423.                 if (TimerTable[index].te_DOW & 2)
  424.                     if (FPuts(fh, "tue ")) {
  425.                         ErrorMsg(MSG_IO_ERROR, filename);
  426.                         Close(fh);
  427.                         return;
  428.                     }
  429.  
  430.                 if (TimerTable[index].te_DOW & 4)
  431.                     if (FPuts(fh, "wed ")) {
  432.                         ErrorMsg(MSG_IO_ERROR, filename);
  433.                         Close(fh);
  434.                         return;
  435.                     }
  436.  
  437.                 if (TimerTable[index].te_DOW & 8)
  438.                     if (FPuts(fh, "thu ")) {
  439.                         ErrorMsg(MSG_IO_ERROR, filename);
  440.                         Close(fh);
  441.                         return;
  442.                     }
  443.  
  444.                 if (TimerTable[index].te_DOW & 16)
  445.                     if (FPuts(fh, "fri ")) {
  446.                         ErrorMsg(MSG_IO_ERROR, filename);
  447.                         Close(fh);
  448.                         return;
  449.                     }
  450.  
  451.                 if (TimerTable[index].te_DOW & 32)
  452.                     if (FPuts(fh, "sat ")) {
  453.                         ErrorMsg(MSG_IO_ERROR, filename);
  454.                         Close(fh);
  455.                         return;
  456.                     }
  457.             }
  458.  
  459.             sprintf(Buf, "hour %02ld ", TimerTable[index].te_Hour);
  460.             if (FPuts(fh, Buf)) {
  461.                 ErrorMsg(MSG_IO_ERROR, filename);
  462.                 Close(fh);
  463.                 return;
  464.             }
  465.  
  466.             sprintf(Buf, "minute %02ld ", TimerTable[index].te_Minute);
  467.             if (FPuts(fh, Buf)) {
  468.                 ErrorMsg(MSG_IO_ERROR, filename);
  469.                 Close(fh);
  470.                 return;
  471.             }
  472.  
  473.             switch (TimerTable[index].te_LevelFunction & 0x0F) {
  474.             case 2:
  475.                 outText = "on";
  476.                 break;
  477.  
  478.             case 3:
  479.                 outText = "off";
  480.                 break;
  481.  
  482.             case 5:
  483.                 sprintf(Buf, "dim %ld", (TimerTable[index].te_LevelFunction >> 4L) + 1);
  484.                 outText = Buf;
  485.                 break;
  486.  
  487.             default:
  488.                 outText = "";
  489.                 break;
  490.             }
  491.  
  492.             if (FPuts(fh, outText)) {
  493.                 ErrorMsg(MSG_IO_ERROR, filename);
  494.                 Close(fh);
  495.                 return;
  496.             }
  497.  
  498.             for (index2 = 0; index2 < 16; index2++)
  499.                 if (HouseCode[index2] == TimerTable[index].te_HouseCode) {
  500.                     sprintf(Buf, " housecode %lc", index2 + 'A');
  501.                     if (FPuts(fh, Buf)) {
  502.                         ErrorMsg(MSG_IO_ERROR, filename);
  503.                         Close(fh);
  504.                         return;
  505.                     }
  506.                 }
  507.  
  508.             for (index2 = 0; index2 < 16; index2++)
  509.                 if (TimerTable[index].te_UnitMap[index2 < 8 ? 0 : 1] & (1L << 7 - (index2 < 8 ? index2 : index2 - 8))) {
  510.                     sprintf(Buf, " %ld", index2 + 1);
  511.                     if (FPuts(fh, Buf)) {
  512.                         ErrorMsg(MSG_IO_ERROR, filename);
  513.                         Close(fh);
  514.                         return;
  515.                     }
  516.                 }
  517.  
  518.             FPutC(fh, '\n');
  519.         }        /* for TimerEvent loop */
  520.  
  521.         sprintf(Buf, GetString(&LocaleInfo, MSG_COMMENT_GRAPHICS), TimerTablePos ? "\n" : "");
  522.         if (FPuts(fh, Buf)) {
  523.             ErrorMsg(MSG_IO_ERROR, filename);
  524.             Close(fh);
  525.             return;
  526.         }
  527.  
  528.         for (index = 0; index < GraphicsTablePos; index++) {
  529.             sprintf(Buf, "graphics %ld %ld\n", GraphicTable[index].gd_Graphic1, GraphicTable[index].gd_Graphic2);
  530.             if (FPuts(fh, Buf)) {
  531.                 ErrorMsg(MSG_IO_ERROR, filename);
  532.                 Close(fh);
  533.                 return;
  534.             }
  535.         }
  536.  
  537.         Close(fh);
  538.     }
  539.     else
  540.         ErrorMsg(MSG_CANT_CREATE_FILE, filename);
  541. }
  542.  
  543. static BOOL SendUploadRequest(BOOL RequestGraphics)
  544. {
  545.     UBYTE Buf[17];
  546.     UWORD raw;
  547.     int index;
  548.  
  549.     memset(Buf, 0xFF, 16);
  550.     Buf[16] = RequestGraphics ? 6 : 5;
  551.  
  552.     ClearSerial();
  553.     SerWrite(Buf, 17);
  554.  
  555.     for (index = 0;;) {
  556.         raw = SerGetRawChar(15);
  557.  
  558.         if (raw == TIMEOUT) {
  559.             ErrorMsg(MSG_CP290_ERROR_NO_RESPONSE);
  560.             return FALSE;
  561.         }
  562.  
  563.         if (raw == 0xFF)
  564.             index++;
  565.         else if (index > 5)
  566.             return TRUE;
  567.     }
  568. }
  569.  
  570. static UWORD ReadNextData(int DataLength, STRPTR Buffer)
  571. {
  572.     UWORD raw;
  573.     UBYTE CheckSum;
  574.     int index;
  575.  
  576.     raw = SerGetRawChar(2);
  577.  
  578.     if (raw == TIMEOUT)
  579.         return TIMEOUT;
  580.  
  581.     if (raw == 0xFF)
  582.         return EMPTY;
  583.     else {            /* an event is stored here */
  584.         Buffer[0] = CheckSum = raw;
  585.  
  586.         for (index = 1; index < DataLength; index++) {
  587.             raw = SerGetRawChar(2);
  588.  
  589.             if (raw == TIMEOUT)
  590.                 return TIMEOUT;
  591.  
  592.             Buffer[index] = raw;
  593.             CheckSum += raw;
  594.         }
  595.  
  596.         return (UWORD) CheckSum;
  597.     }
  598. }
  599.